/*
 * JenaToContextTranslator.java
 *
 * Created on 3 de julio de 2006, 14:17
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package ocp.management;

import ocp.service.Interval;
import com.hp.hpl.jena.ontology.*;
import com.hp.hpl.jena.rdf.model.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Enumeration;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import ocp.context.*;


/** 
 * This class translates Jena stored information into Contextual information.
 * @author Ignacio Nieto Carvajal
 */
public class JenaToContextTranslator {

    protected OntModel model;
    protected static final String modelName = "file://eu/popeye/resources/context.owl#"; //"http://www.owl-ontologies.com/unnamed.owl#";
    protected Vector<ContextClass> contextClasses;
    protected Vector<ContextPropertyDefinition> contextPropertyDefinitions;
    protected Vector<ContextualInformation> contextualInformations;

    /** Creates a new instance of JenaToContextTranslator */
    public JenaToContextTranslator(OntModel model) {
        this.contextClasses = new Vector<ContextClass>();
        this.contextPropertyDefinitions = new Vector<ContextPropertyDefinition>();
        this.contextualInformations = new Vector<ContextualInformation>();
        this.model = model;
    }

    // TODO: Mecanismo que borre la información contextual con cada pedida.
    /**
     * gets a simple context from the jena database.
     * @param id the unique id of the simple context resource to retrieve.
     */
    public SimpleContext getSimpleContext(String id) throws ContextException {
        if ((id == null) || (id.equals(""))) {
            throw new ContextException("Unable to get the simple context: void or null id received.");
        }
        Individual scInd = model.getIndividual(id);
        return getSimpleContext(scInd);
    }

    
    /**
     * Comprueba si un contexto existe en la bbdd
     * @param id id del contexto
     * @return true si el contexto existe en la bbdd
     */
    public boolean containsContext(String id) {
        try {
            return getContext(id) != null;
        } catch (ContextException ex) {
            return false;
        }
    }
    
    // TODO: Método para coger un contexto, sea sencillo o complejo, para no tener
    // que discriminar.
    /**
     * gets a context from the jena database.
     */
    public Context getContext(String id) throws ContextException {
        if ((id == null) || (id.equals(""))) {
            throw new ContextException("Unable to get the complex context: void or null id received.");
        }
        Resource res = model.getResource(id);
        ObjectProperty contextstry = model.getObjectProperty(modelName + "contexts");
        ObjectProperty datatry = model.getObjectProperty(modelName + "data");
        if (res.hasProperty(contextstry)) {
            // subcontext is a complex context
            return getComplexContext(res);
        } else if (res.hasProperty(datatry)) {
            // subcontext is a simple context
            return getSimpleContext(res);
        } else {
            throw new ContextException("Unknown context requested!");
        }
    }

    /**
     * gets a simple context from the jena database.
     * @param scres A resource representing the simple context.
     */
    private SimpleContext getSimpleContext(Resource scres) throws ContextException {
        SimpleContext sc;
        if (scres == null) {
            throw new ContextException("Simple context does not exists in the database.");
        }
        String name = scres.getProperty(model.getDatatypeProperty(modelName + "name")).getString();
        String id = scres.getProperty(model.getDatatypeProperty(modelName + "id")).getString();
        sc = new SimpleContext(name, id);

        // component addresses: notifierInformatio + sourceInformation
        ComponentAddress si = getComponentAddress(scres, modelName + "notifierInformation");
        ComponentAddress ni = getComponentAddress(scres, modelName + "sourceInformation");
        sc.setSourceInformation(si);
        sc.setNotifierInformation(ni);
        // contextual information: data
        ContextualInformationList cil = getContextualInformationList(scres, id);
        sc.addContextualInformationList(cil);
        return sc;
    }

    /**
     * gets a complex context from the jena database.
     * @param id the unique id of the complex context resource to retrieve.
     */
    public ComplexContext getComplexContext(String id) throws ContextException {
        if ((id == null) || (id.equals(""))) {
            throw new ContextException("Unable to get the complex context: void or null id received.");
        }
        Individual ccInd = model.getIndividual(id);
        return getComplexContext(ccInd);
    }

    /**
     * gets a complex context from the jena database.
     * @param res the resource representing this complex context.
     */
    private ComplexContext getComplexContext(Resource ccInd) throws ContextException {
        ComplexContext cc;
        if (ccInd == null) {
            throw new ContextException("Complex context does not exists in the database.");
        }
        String name = ccInd.getProperty(model.getDatatypeProperty(modelName + "name")).getString();
        String id = ccInd.getProperty(model.getDatatypeProperty(modelName + "id")).getString();
        cc = new ComplexContext(name, id, new SimpleContextMerger());
        //--
        String dateTime = ccInd.getProperty(model.getDatatypeProperty(modelName + "time")).getString();
        cc.updateDateTime(dateTime);
        //--
        // component addresses: notifierInformatio + sourceInformation
        ComponentAddress si = getComponentAddress(ccInd, modelName + "notifierInformation");
        ComponentAddress ni = getComponentAddress(ccInd, modelName + "sourceInformation");
        cc.setSourceInformation(si);
        cc.setNotifierInformation(ni);
        // contexts
        // we must take into account if the context is a simple or complex context.
        ObjectProperty contextsProp = model.getObjectProperty(modelName + "contexts");
        Selector selector = new SimpleSelector(ccInd, contextsProp, (Resource) null);
        StmtIterator stmti = model.listStatements(selector);
        ObjectProperty contextstry = model.getObjectProperty(modelName + "contexts");
        ObjectProperty datatry = model.getObjectProperty(modelName + "data");
        while (stmti.hasNext()) {
            Resource res = stmti.nextStatement().getResource();
            if (res.hasProperty(contextstry)) {
                // subcontext is a complex context
                ComplexContext subcc = getComplexContext(res);
                cc.addContext(subcc);
            } else if (res.hasProperty(datatry)) {
                // subcontext is a simple context
                SimpleContext subsc = getSimpleContext(res);
                cc.addContext(subsc);
            } else {
                throw new ContextException("Unknown context type in subcontext " + id + "->" + res.getProperty(model.getDatatypeProperty(modelName + "id")).getString());
            }
        }
        return cc;
    }

    /**
     * gets a component address from the jena database.
     * @param scInd Individual resource representing the simple context from wich get the component address.
     * @param propName name of the property in the form of a component address to retrieve.
     */
    private ComponentAddress getComponentAddress(Resource scInd, String propName) throws ContextException {
        Property prop = model.getProperty(propName);
        if (prop == null) {
            throw new ContextException("Property " + propName + " does not exists in the model!");
        }
        Statement stmtprop = scInd.getProperty(prop);
        if (stmtprop == null) {
            return null;
        }
        Resource ca = stmtprop.getResource();
        if (ca == null) {
            return null; //throw new ContextException("SimpleContext "+scInd.getId()+" does not have property "+propName);
        }
        DatatypeProperty idProp = model.getDatatypeProperty(modelName + "id");
        DatatypeProperty addProp = model.getDatatypeProperty(modelName + "address");
        Statement idStmt = ca.getProperty(idProp);
        if (idStmt == null) {
            return null;
        }
        Statement adStmt = ca.getProperty(addProp);
        if (adStmt == null) {
            return null;
        }
        String id = idStmt.getString();
        String address = adStmt.getString();
        return new ComponentAddress(id, address);
    }

    /**
     * gets the contextual information of a simple context in form of a contextual information list.
     */
    private ContextualInformationList getContextualInformationList(Resource scInd, String id) throws ContextException {
        ObjectProperty dataProp = model.getObjectProperty(modelName + "data");
        ContextualInformationList cil = new ContextualInformationList();
        for (StmtIterator i = scInd.listProperties(dataProp); i.hasNext();) {
            ContextualInformation ci = getContextualInformation(i.nextStatement().getResource());
            cil.addContextualInformation(ci);
        }
        return cil;
    }

    /**
     * gets a contextual information from a simple context.
     */
    private ContextualInformation getContextualInformation(Resource ciRes) throws ContextException {
        // class, name, description
        ObjectProperty classProp = model.getObjectProperty(modelName + "class");
        Statement classStmt = ciRes.getProperty(classProp);
        if (classStmt == null) {
            return null;
        }
        Resource classRes = classStmt.getResource();
        ContextClass cc = getContextClass(classRes);
        DatatypeProperty nameProp = model.getDatatypeProperty(modelName + "name");
        Statement nameStmt = ciRes.getProperty(nameProp);
        if (nameStmt == null) {
            return null;
        }
        String name = nameStmt.getString();
        DatatypeProperty descProp = model.getDatatypeProperty(modelName + "description");
        Statement desStmt = ciRes.getProperty(descProp);
        if (desStmt == null) {
            return null;
        }
        String description = desStmt.getString();
        ContextualInformation ci = searchContextualInformation(name, cc);
        ci = null;
        if (ci == null) {
            ci = new ContextualInformation(cc, name, description);
            ObjectProperty aProp = model.getObjectProperty(modelName + "attributes");
            StmtIterator stmti = ciRes.listProperties(aProp);
            while (stmti.hasNext()) {
                Statement stmtRes = stmti.nextStatement();
                if (stmtRes != null) {
                    Resource aRes = stmtRes.getResource();
                    Attribute a = getAttribute(aRes);
                    if (a != null) {
                        ci.addAttribute(a);
                    }
                }
            }
            ObjectProperty diProp = model.getObjectProperty(modelName + "differentInstances");
            stmti = ciRes.listProperties(diProp);
            while (stmti.hasNext()) {
                Resource diRes = stmti.nextStatement().getResource();
                ContextualInformation diCi = getContextualInformation(diRes);
                if (diCi != null) {
                    ci.addDifferentInstance(diCi);
                }
            }
            ObjectProperty eqProp = model.getObjectProperty(modelName + "equivalentInstances");
            stmti = ciRes.listProperties(eqProp);
            while (stmti.hasNext()) {
                Resource eqRes = stmti.nextStatement().getResource();
                ContextualInformation eqCi = getContextualInformation(eqRes);
                if (eqCi != null) {
                    ci.addEquivalentInstance(eqCi);
                }
            }
            ObjectProperty propsProp = model.getObjectProperty(modelName + "properties");
            stmti = ciRes.listProperties(eqProp);
            while (stmti.hasNext()) {
                Resource prRes = stmti.nextStatement().getResource();
                System.err.println("Una propiedad encontrada: " + prRes.toString());
                ContextProperty prop = getContextProperty(prRes);
                System.err.println("Prop es: " + prop.toXML());
                if (prop != null) {
                    ci.addProperty(prop);
                }
            }
            contextualInformations.addElement(ci);
        }
        return ci;
    }

    private synchronized ContextClass getContextClass(Resource classRes) throws ContextException {
        DatatypeProperty nameProp = model.getDatatypeProperty(modelName + "name");
        Statement nameStmt = classRes.getProperty(nameProp);
        if (nameStmt == null) {
            return null;
        }
        String name = nameStmt.getString();
        ContextClass cc = searchContextClass(name);
        if (cc == null) {
            StmtIterator stmti;
            cc = new ContextClass(name);
            ObjectProperty scProp = model.getObjectProperty(modelName + "superClass");
            Statement scResStm = classRes.getProperty(scProp);
            if (scResStm != null) {
                Resource scRes = scResStm.getResource();
                if (scRes != null) {
                    ContextClass superClass = getContextClass(scRes);
                    cc.setSuperClass(superClass);
                }
            }
            ObjectProperty ecProp = model.getObjectProperty(modelName + "equivalentClasses");
            stmti = classRes.listProperties(ecProp);
            while (stmti.hasNext()) {
                Resource ec = stmti.nextStatement().getResource();
                ContextClass ecc = getContextClass(ec);
                if (ecc != null) {
                    cc.isEquivalentTo(getContextClass(ec));
                }
            }
            ObjectProperty adProp = model.getObjectProperty(modelName + "attributeDefinitions");
            stmti = classRes.listProperties(adProp);
            while (stmti.hasNext()) {
                Resource adRes = stmti.nextStatement().getResource();
                AttributeDefinition ad = getAttributeDefinition(adRes);
                if (ad != null) {
                    cc.addAttributeDefinition(ad);
                }
            }
            ObjectProperty ioProp = model.getObjectProperty(modelName + "intersectionOf");
            stmti = classRes.listProperties(ioProp);
            while (stmti.hasNext()) {
                Resource ioRes = stmti.nextStatement().getResource();
                ContextPropertyDefinition io = getContextPropertyDefinition(ioRes);
                if (io != null) {
                    cc.addPropertyDefinition(io);
                }
            }
            ObjectProperty pdProp = model.getObjectProperty(modelName + "propertyDefinitions");
            stmti = classRes.listProperties(pdProp);
            while (stmti.hasNext()) {
                Resource pdRes = stmti.nextStatement().getResource();
                ContextPropertyDefinition pd = getContextPropertyDefinition(pdRes);
                if (pd != null) {
                    cc.addPropertyDefinition(pd);
                }
            }
            contextClasses.add(cc);
        }
        return cc;
    }

    private ContextPropertyDefinition getContextPropertyDefinition(Resource ioRes) throws ContextException {
        DatatypeProperty nameProp = model.getDatatypeProperty(modelName + "name");
        String name = ioRes.getProperty(nameProp).getString();
        ContextPropertyDefinition cpd = searchPropertyDefinition(name);
        if (cpd != null) {
            return cpd;
        }
        // TODO: Devuelve todos a false, revisar!
        cpd = new ContextPropertyDefinition(name);
        DatatypeProperty hasInvProp = model.getDatatypeProperty(modelName + "hasInverse");
        DatatypeProperty funProp = model.getDatatypeProperty(modelName + "functional");
        DatatypeProperty symProp = model.getDatatypeProperty(modelName + "symmetric");
        DatatypeProperty traProp = model.getDatatypeProperty(modelName + "transitive");
        Statement fProp = ioRes.getProperty(funProp);
        if (fProp != null) {
            cpd.setFunctional(fProp.getBoolean());
        }
        Statement sProp = ioRes.getProperty(symProp);
        if (sProp != null) {
            cpd.setSymmetric(sProp.getBoolean());
        }
        Statement tProp = ioRes.getProperty(traProp);
        if (tProp != null) {
            cpd.setSymmetric(tProp.getBoolean());
        }
        ObjectProperty invProp = model.getObjectProperty(modelName + "inverse");
        Statement iProp = ioRes.getProperty(hasInvProp);
        boolean hasInv = iProp == null ? false : iProp.getBoolean();
        if (hasInv) {
            Statement invStmt = ioRes.getProperty(invProp);
            if (invStmt == null) {
                cpd.removeInverse();
            } else {
                ContextPropertyDefinition inverseCpd = getContextPropertyDefinition(invStmt.getResource());
                cpd.setInverse(inverseCpd);
            }
        } else {
            cpd.removeInverse();
        }
        ObjectProperty domainsProp = model.getObjectProperty(modelName + "domains");
        ObjectProperty rangesProp = model.getObjectProperty(modelName + "ranges");
        StmtIterator i = ioRes.listProperties(domainsProp);
        while (i.hasNext()) {
            Resource domRes = i.nextStatement().getResource();
            ContextPropertySpace domain = getContextSpace(domRes);
            if (domain != null) {
                cpd.addDomain(domain);
            }
        }
        i = ioRes.listProperties(rangesProp);
        while (i.hasNext()) {
            Resource ranRes = i.nextStatement().getResource();
            ContextPropertySpace range = getContextSpace(ranRes);
            if (range != null) {
                cpd.addRange(range);
            }
        }
        // añadir el resultado a la lista contextPropertyDefinitions
        contextPropertyDefinitions.addElement(cpd);
        return cpd;
    }

    private AttributeDefinition getAttributeDefinition(Resource adRes) {

        String name;
        String type;

        DatatypeProperty nameProp = model.getDatatypeProperty(modelName + "name");
        DatatypeProperty typeProp = model.getDatatypeProperty(modelName + "type");
        Statement nameStmt = adRes.getProperty(nameProp);
        Statement typeStmt = adRes.getProperty(typeProp);
        if (nameStmt == null) {
            return null;
        } else {
            name = nameStmt.getString();
        }
        if (typeStmt == null) {
            return null;
        } else {
            type = typeStmt.getString();
        }
        AttributeDefinition ad = new AttributeDefinition(name, type);

        return ad;
    }

    private Attribute getAttribute(Resource aRes) throws ContextException {
        ObjectProperty adProp = model.getObjectProperty(modelName + "attributeDefinition");
        DatatypeProperty avProp = model.getDatatypeProperty(modelName + "value");

        try {
            Statement adStmt = aRes.getProperty(adProp);
            if (adStmt == null) {
                return null;
            }
            Resource adRes = adStmt.getResource();
            Statement avStmt = aRes.getProperty(avProp);
            if (avStmt == null) {
                return null;
            }
            AttributeDefinition ad = getAttributeDefinition(adRes);
            if (ad == null) {
                return null;
            }

            RDFNode node = avStmt.getObject();
            Object object = null;

            if (!(node instanceof Resource)) {
                Literal literal = avStmt.getLiteral();
                if (literal.getDatatype().isValid(literal.getLexicalForm())) {
                    object = literal.getDatatype().parse(literal.getLexicalForm());
                    /*
                   if( ad.getName().equalsIgnoreCase("identify") )  {
                      System.out.println( "JENA1 >>>>> tipo:" +  literal.getDatatype().getJavaClass().getName() + " LexicalForm:" + literal.getLexicalForm());
                    
                      System.out.println( "JENA2 >>>>> tipo1:" +  object.getClass().getName());
                      object = literal.getValue();
                      System.out.println( "JENA3 >>>>> tipo2:" +  object.getClass().getName());
                   }*/
                }
            }
            return new Attribute(ad, object);
        } catch (Exception ce) {
            ce.printStackTrace();
            throw new ContextException(ce.getMessage());
        }
    }

    private ContextPropertySpace getContextSpace(Resource csRes) throws ContextException {
        DatatypeProperty maxProp = model.getDatatypeProperty(modelName + "maxCardinality");
        DatatypeProperty minProp = model.getDatatypeProperty(modelName + "minCardinality");
        DatatypeProperty rtProp = model.getDatatypeProperty(modelName + "restrictionType");
        DatatypeProperty classProp = model.getDatatypeProperty(modelName + "class");

        int type;
        Statement maxStmt = csRes.getProperty(maxProp);
        if (maxStmt == null) {
            return null;
        }
        int max = maxStmt.getInt();
        Statement minStmt = csRes.getProperty(minProp);
        if (minStmt == null) {
            return null;
        }
        int min = minStmt.getInt();
        Statement rtStmt = csRes.getProperty(rtProp);
        if (rtStmt == null) {
            return null;
        }
        String rt = rtStmt.getString();
        if (rt.equals(ContextPropertySpace.names[ContextPropertySpace.ALL_VALUES_FROM])) {
            type = ContextPropertySpace.ALL_VALUES_FROM;
        } else if (rt.equals(ContextPropertySpace.names[ContextPropertySpace.SOME_VALUES_FROM])) {
            type = ContextPropertySpace.SOME_VALUES_FROM;
        } else {
            type = ContextPropertySpace.NOT_DEFINED;
        }
        Statement ccresStmt = csRes.getProperty(classProp);
        if (ccresStmt == null) {
            return null;
        }
        String className = ccresStmt.getString();

        ContextPropertySpace cs = new ContextPropertySpace(className, min, max, type);
        return cs;
    }

    private ContextProperty getContextProperty(Resource prRes) throws ContextException {
        ObjectProperty diProp = model.getObjectProperty(modelName + "domainInstances");
        ObjectProperty riProp = model.getObjectProperty(modelName + "rangeInstances");
        ObjectProperty pdProp = model.getObjectProperty(modelName + "propertyDefinition");

        Statement pdresStmt = prRes.getProperty(pdProp);
        if (pdresStmt == null) {
            return null;
        }
        Resource pdRes = pdresStmt.getResource();
        ContextPropertyDefinition cpd = getContextPropertyDefinition(pdRes);

        Vector domInstances = new Vector();
        Vector ranInstances = new Vector();
        System.err.println("Antes: cpd es " + cpd.toString());
        StmtIterator i = prRes.listProperties(diProp);
        while (i.hasNext()) {
            Resource diRes = i.nextStatement().getResource();
            ContextualInformation di = getContextualInformation(diRes);
            System.err.println("domain instance: " + di.toString());
            domInstances.addElement(di);
        }
        i = prRes.listProperties(riProp);
        while (i.hasNext()) {
            Resource riRes = i.nextStatement().getResource();
            ContextualInformation ri = getContextualInformation(riRes);
            System.err.println("domain instance: " + ri.toString());
            ranInstances.addElement(ri);
        }
        try {
            return new ContextProperty(cpd, domInstances, ranInstances);
        } catch (ContextException ex) {
            ex.printStackTrace();
            throw new ContextException(ex.getMessage());
        }
    }

    /**
     * searchs for a context class in contextClasses.
     */
    private synchronized ContextClass searchContextClass(String name) {
        for (int i = 0; i < contextClasses.size(); i++) {
            ContextClass cc = contextClasses.elementAt(i);
            if (cc.getName().equals(name)) {
                return cc;
            }
        }
        return null;
    }

    /**
     * searchs for a contextualInformation in contextualInformations.
     */
    private synchronized ContextualInformation searchContextualInformation(String name, ContextClass cc) {
        for (Enumeration<ContextualInformation> e = contextualInformations.elements(); e.hasMoreElements();) {
            ContextualInformation ci = e.nextElement();
            if ((ci.getName().equals(name)) && (ci.getContextClass().equals(cc))) {
                return ci;
            }
        }
        return null;
    }

    private synchronized ContextPropertyDefinition searchPropertyDefinition(String name) {
        for (Enumeration<ContextPropertyDefinition> e = contextPropertyDefinitions.elements(); e.hasMoreElements();) {
            ContextPropertyDefinition cpd = e.nextElement();
            if (cpd.getName().equals(name)) {
                return cpd;
            }
        }
        return null;
    }

    /**
     * gets a historicalContext from the jena database.
     */
    public Vector getHContext(String id, long begin, long end) throws ContextException {

        if ((id == null) || (id.equals(""))) {
            throw new ContextException("Unable to get the complex context: void or null id received.");
        }

        Individual simpleInd = model.getIndividual("historical" + id);
        if (simpleInd == null) {
            throw new ContextException("Unknown historical context requested!");
        }

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd\'T\'HH:mm:ss");
        String dateStr = "";
        long instant;

        Vector contexts = new Vector();
        ObjectProperty hContexts = model.getObjectProperty(modelName + "hContexts");
        NodeIterator it = simpleInd.listPropertyValues(hContexts);
        while (it.hasNext()) {
            try {
                RDFNode node = it.nextNode();
                Context c = getContext(node.toString());
                dateStr = c.getId().substring(c.getId().lastIndexOf("|") + 1);
                instant = sdf.parse(dateStr).getTime();
                if (instant >= begin && instant <= end) {
                    contexts.addElement(c);
                }
            } catch (ParseException ex) {
                ex.printStackTrace();
                Logger.getLogger(JenaToContextTranslator.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return contexts;
    }

    /**
     * Counts the items stored in the historical for one Context.
     */
    public int getCountHistorical(String contextName) throws ContextException {

        if ((contextName == null) || (contextName.equals(""))) {
            throw new ContextException("Unable to get the context: void or null id received.");
        }

        Individual simpleInd = model.getIndividual("historical" + contextName);
        if (simpleInd == null) {
            throw new ContextException("Unknown historical context requested!");
        }

        ObjectProperty hContexts = model.getObjectProperty(modelName + "hContexts");
        return simpleInd.getCardinality(hContexts);
    }

    /**
     * Counts the items stored in the historical for one Context.
     */
    public Context getHistoricalByIndex(String contextName, int index) throws ContextException {

        if ((contextName == null) || (contextName.equals(""))) {
            throw new ContextException("Unable to get the context: void or null id received.");
        }

        Individual simpleInd = model.getIndividual("historical" + contextName);
        if (simpleInd == null) {
            throw new ContextException("Unknown historical context requested!");
        }

        ObjectProperty hContexts = model.getObjectProperty(modelName + "hContexts");

        if (simpleInd.getCardinality(hContexts) == 0) {
            throw new ContextException("historical context is empty!");
        }

        if (index > simpleInd.getCardinality(hContexts)) {
            throw new ContextException("Not exist historical context for this index!");
        }

        RDFNode node = null;
        NodeIterator it = simpleInd.listPropertyValues(hContexts);
        int i = 0;
        while (it.hasNext() && i++ < index) {
            node = it.nextNode();
        }
        return getContext(node.toString());
    }

    /**
     * Get this interval in wich the historical has information.
     */
    public Interval getHistoricalInterval(String contextName) throws ContextException {
        try {

            if ((contextName == null) || (contextName.equals(""))) {
                throw new ContextException("Unable to get the context: void or null id received.");
            }

            Individual simpleInd = model.getIndividual("historical" + contextName);
            if (simpleInd == null) {
                throw new ContextException("Unknown historical context requested!");
            }

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd\'T\'HH:mm:ss");
            String dateStr = "";
            long instant;
            long begin;
            long end;
            RDFNode node;

            ObjectProperty hContexts = model.getObjectProperty(modelName + "hContexts");
            NodeIterator it = simpleInd.listPropertyValues(hContexts);

            if (!it.hasNext()) {
                throw new ContextException("historical context is empty!");
            }

            node = it.nextNode();
            dateStr = node.toString().substring(node.toString().lastIndexOf("|") + 1);
            begin = end = sdf.parse(dateStr).getTime();

            while (it.hasNext()) {
                node = it.nextNode();
                dateStr = node.toString().substring(node.toString().lastIndexOf("|") + 1);
                instant = sdf.parse(dateStr).getTime();
                if (instant > end) {
                    end = instant;
                } else if (instant < begin) {
                    begin = instant;
                }
            }

            return new Interval(begin, end);
        } catch (ParseException ex) {
            ex.printStackTrace();
            Logger.getLogger(JenaToContextTranslator.class.getName()).log(Level.SEVERE, null, ex);
            return null;
        }
    }
}